/*  File Name	: ChatMonitor.cpp
 *  Author		: Javie Pong
 *	 E-mail		: 823960168@qq.com
 *  Created on	: 2012-10-4
 *  Description:
 */

#include "ChatMonitor.h"
#include "Reactor.h"
#include "EpollReactor.h"
#include "MySqlDB.h"

ChatMonitor* ChatMonitor::instance_= NULL;

ChatMonitor::ChatMonitor()
{
	this->acceptor_ = NULL;
	this->line_id_ = -1;
	this->player_map_.clear();
	this->table_map_.clear();
}

ChatMonitor::~ChatMonitor()
{
	this->player_pool_.recycle();
}

const Json::Value &ChatMonitor::cfg(void)
{
#ifdef DEBUG
	return CONFIG_INSTANCE->chat()["debug"][this->line_id_];

#else
	return CONFIG_INSTANCE->chat()["online"][this->line_id_];
#endif
}


ChatMonitor* ChatMonitor::instance(void)
{
	if(NULL==instance_)
	{
		instance_ = new ChatMonitor();
	}
	return instance_;
}

int ChatMonitor::run_request_loop(void)
{
	while(true)
	{
		if(this->reactor()->run_status()==2)
		{
			LOG((INFO_LOG,"ChatMonitor::run_request_loop exit"));
			return 0;
		}

		MessageBlock *mb = NULL;
		this->request_mb_pop(mb);
		if (NULL != mb)
		{
			this->process_request(mb);
			this->msg_pool()->push(mb);
		}
		else
		{
			usleep(1000);
		}
	}
	return 0;
}

int ChatMonitor::run_respond_loop(void)
{
	while(true)
	{
		if(this->reactor()->run_status()==2)
		{
			LOG((INFO_LOG,"ChatMonitor::run_respond_loop exit"));
			return 0;
		}

		MessageBlock *mb = NULL;
		this->respond_mb_pop(mb);
		if(NULL!=mb)
		{
			this->process_respond(mb);
			this->msg_pool()->push(mb);
		}
		else
		{
			usleep(1000);
		}
	}
	return 0;
}

int ChatMonitor::init(int line_id, int list_size, int block_size, int pool_size,
		int growth_size, std::string pool_name)
{
	this->line_id_ = line_id;
	super::init(list_size, block_size, pool_size, growth_size, pool_name);

	this->acceptor_ = new ChatAcceptor();
	if(NULL==this->acceptor_)
	{
		return -1;
	}

	//request thread
	int req_thr = this->cfg()["request_thr"].asInt();
	this->create_request_thr(req_thr,"ChatMonitor::request",false);

	//respond thread
	int res_thr = this->cfg()["respond_thr"].asInt();
	this->create_respond_thr(res_thr,"ChatMonitor::respond",false);

	this->reactor(Reactor::instance());
	if (NULL == this->reactor()->implement())
	{
		this->reactor()->implement(new EpollReactor(10000, 102400));
	}

	return 0;
}

int ChatMonitor::start(void)
{
	super::start();

	int port = this->cfg()["port"].asInt();
	if(this->acceptor_->open(port,this->reactor())<0)
	{
		return -1;
	}
#ifndef DEBUG

	this->reactor()->run_reactor_loop();
	this->wait_thread_exit();

#endif
	return 0;
}

int ChatMonitor::stop(void)
{
	this->reactor()->end_reactor_loop();
	return super::stop();
}

ChatPlayer *ChatMonitor::find_player(int roleid)
{
	PlayerMap::iterator iter = this->player_map_.find(roleid);
	if (iter != this->player_map_.end())
	{
		return iter->second;
	}
	return NULL;
}


int ChatMonitor::bind_player(int roleid,ChatPlayer *player)
{
	if(this->find_player(roleid)==NULL)
	{
		this->player_map_.insert(std::pair<int,ChatPlayer*>(roleid,player));
		this->bind_table(player);
		return 0;
	}
	return -1;
}

int ChatMonitor::unbind_player(int roleid)
{
	ChatPlayer *player = this->find_player(roleid);
	if(player!=NULL)
	{
		this->unbind_table(player);
		this->player_map_.erase(roleid);
		this->player_pool_.push(player);
		return 0;
	}
	return -1;
}

int ChatMonitor::bind_table(ChatPlayer *player)
{
	if(NULL==player)
	{
		return -1;
	}
	TableMap::iterator iter=this->table_map_.find(player->table);
	if(iter==this->table_map_.end())
	{
		PlayerMap map;
		map.insert(std::pair<int,ChatPlayer*>(player->roleid,player));
		this->table_map_.insert(std::pair<int,PlayerMap>(player->table,map));
	}
	else
	{
		iter->second.insert(std::pair<int,ChatPlayer*>(player->roleid,player));
	}
	return 0;
}

int ChatMonitor::unbind_table(ChatPlayer *player)
{
	if(NULL==player)
	{
		return -1;
	}
	TableMap::iterator iter = this->table_map_.find(player->table);
	if (iter != this->table_map_.end())
	{
		PlayerMap::iterator player_iter = iter->second.find(player->roleid);
		if(player_iter==iter->second.end())
		{
			return -1;
		}
		iter->second.erase(player->roleid);
	}
	return 0;
}

int ChatMonitor::process_request(MessageBlock *mb)
{
	int svc_id = 0,role_id=0, cmd = 0,remain=0;
	*mb >> svc_id >> role_id >>cmd >> remain;

	ChatService *gs = this->find_service(svc_id);
	if (NULL==gs)
	{
		LOG((ERROR_LOG,"ChatMonitor::process_request-->can't find svc"));
		return -1;
	}
	LOG((INFO_LOG,"ChatMonitor::process_request-->[cmd:%d][role:%d][from:%s:%d]",
			cmd,role_id,gs->peer_addr(),gs->peer_port()));

	switch(cmd)
	{
		case CHATER_LOG_IN:
		{
			return this->login(svc_id,mb);
		}
		case CHATER_LOG_OUT:
		{
			return this->logout(role_id);
		}
		default:
		{
			return this->chat(role_id,mb);
		}
	}
	return 0;
}

int ChatMonitor::process_respond(MessageBlock *mb)
{
	int svc_id =0,cmd =0;
	*mb >> svc_id>>cmd;
	LOG((DEBUG_LOG,"ChatMonitor::process_respond-->[cmd:%d][%d][%d]",cmd,svc_id,mb->data_len()));
	return 0;
}

void ChatMonitor::collection_info(void)
{

}

int ChatMonitor::login(int svcid,MessageBlock *mb)
{
	ChatService *service = this->find_service(svcid);
	if (NULL != service)
	{
		return service->handle_close();
	}

	int roleid = 0;
	*mb >> roleid;

	bool is_new = true;

	int room = 0,table = 0;
	*mb >> room >>table;

	LockGuardReturn(RT_MUTEX,lock,this->rt_mutex_,-1);
	ChatPlayer *player = this->find_player(roleid);
	if(player==NULL)
	{
		if(this->player_pool_.pop(player)<0)
		{
			return service->handle_close();
		}
		service->role_id(roleid);
	}
	else
	{
		if(service->role_id()!=roleid)
		{
			this->player_pool_.push(player);
			return service->handle_close();
		}
		is_new = false;
	}
	player->reset();
	player->svcid = svcid;
	player->roleid = roleid;
	player->svc = service;
	player->room = room;
	player->table = table;
	this->bind_player(roleid,player);
	return 0;
}

int ChatMonitor::logout(int roleid)
{
	LockGuardReturn(RT_MUTEX,lock,this->rt_mutex_,-1);

	return this->unbind_player(roleid);
}

int ChatMonitor::chat(int roleid,MessageBlock *mb)
{
	ChatPlayer *player =this->find_player(roleid);
	if(NULL==player)
	{
		return 0;
	}
	return this->broadcast_to_table(player->table,mb);
}

int ChatMonitor::broadcast_to_table(int table,MessageBlock *mb)
{
	MessageBlock mb_send(mb->left_rd_len()+sizeof(int)*4);

	mb_send << 0 << STC_CHATER_CONTENT << 0;
	mb_send.write(mb->rd_ptr(),mb->left_rd_len());
	::memcpy(mb_send.base_ptr(),"%d",mb_send.data_len());

	TableMap::iterator iter = this->table_map_.find(table);
	if (iter != this->table_map_.end())
	{
		for(PlayerMap::iterator iter_p = iter->second.begin();
				iter_p!=iter->second.end();iter_p++)
		{
			iter_p->second->svc->send_msg(&mb_send,mb_send.data_len());
		}
	}
	return 0;
}
